Pattern數量已經接近尾聲了,今天就是Visitor Pattern了!
Visitor Pattern,正常來說是透過Overload來達到不同物件有不同回應,那我之前在使用上,是有不同類型的物品但會有不同的優惠,才使用到Visitor Pattern。在Typescript原始狀態是沒有Overload這功能的,似乎因為js原本就沒有class型別,所以就...但我認為在一OO語言上必須要有,所以..可以去NPM補一下,就可以有辦法解。但因為這只是一個體驗,所以我並沒有裝,是有用if判斷模擬overload狀況。
首先先定義一下,每一個組件都必須有accept且可將自己包進去要求visit。
//ComputerPart.ts
import {ComputerPartVisitor} from './ComputerPartVisitor';
export interface ComputerPart{
    accept(computerPartVisitor:ComputerPartVisitor):void;
}
鍵盤、滑鼠、螢幕
//Keyboard.ts
import {ComputerPart} from './ComputerPart';
import {ComputerPartVisitor} from './ComputerPartVisitor';
export class Keyboard implements ComputerPart{
    public accept(computerPartVisitor:ComputerPartVisitor):void{
        computerPartVisitor.visit(this);
    }
}
//Mouse.ts
import {ComputerPart} from './ComputerPart';
import {ComputerPartVisitor} from './ComputerPartVisitor';
export class Mouse implements ComputerPart{
    public accept(computerPartVisitor:ComputerPartVisitor):void{
        computerPartVisitor.visit(this);
    }
}
//Monitor.ts
import {ComputerPart} from './ComputerPart';
import {ComputerPartVisitor} from './ComputerPartVisitor';
export class Monitor implements ComputerPart{
    public accept(computerPartVisitor:ComputerPartVisitor):void{
        computerPartVisitor.visit(this);
    }
}
Computer是一Composite的感覺,裡面可以塞一堆組件。
//Computer.ts
import {ComputerPart} from './ComputerPart';
import {ComputerPartVisitor} from './ComputerPartVisitor';
import {Keyboard} from './Keyboard';
import {Monitor} from './Monitor';
import {Mouse} from './Mouse';
export class Computer implements ComputerPart{
    private parts:ComputerPart[];
    constructor(){
        this.parts = [new Keyboard(),new Monitor(),new Mouse()];
    }
    public accept(computerPartVisitor:ComputerPartVisitor):void{
        this.parts.forEach( (part) => {
            part.accept(computerPartVisitor);
          });
          computerPartVisitor.visit(this);
    }
}
針對四種不同的物件,理想以Overload解決。
//ComputerPartVisitor.ts
import {Keyboard} from './Keyboard';
import {Mouse} from './Mouse';
import {Monitor} from './Monitor';
import {Computer} from './Computer';
export interface ComputerPartVisitor{
    visit(computer:Keyboard):void;
    visit(mouse:Mouse):void;
    visit(keyboard:Keyboard):void;
    visit(monitor:Monitor):void;
}
這邊的就是為了因應Typescript寫的了,並不是標準解。
//ComputerPartDisplayVisitor.ts
import {ComputerPartVisitor} from './ComputerPartVisitor';
import {Computer} from './Computer';
import {Mouse} from './Mouse';
import {Keyboard} from './Keyboard';
import {Monitor} from './Monitor';
import {ComputerPart} from './ComputerPart';
export class ComputerPartDisplayVisitor implements ComputerPartVisitor{
    
     visit(part:ComputerPart):void {
        let partType = part.constructor.toString().match(/\w+/g)[1]
        //判斷物件名稱
        switch(partType) { 
            case 'Computer': { 
               this.visit1(<Computer>part);
               break; 
            } 
            case 'Mouse': { 
                this.visit2(<Mouse>part);
               break; 
            } 
            case 'Keyboard': { 
                this.visit3(<Keyboard>part);
                break; 
             } 
            case 'Monitor': { 
                this.visit4(<Monitor>part);
                break; 
             } 
            default: { 
               console.log('something error');
               break; 
            } 
         } 
     }
    private visit1(computer:Computer):void {
        console.log('Displaying Computer');
     }
    private visit2(mouse:Mouse):void {
        console.log('Displaying Mouse');
    }
    private visit3(keyboard:Keyboard):void {
        console.log('Displaying Keyboard');
    }
    private visit4(monitor:Monitor):void {
        console.log('Displaying Monitor');
    }
}
Demo!
//Demo.ts
import {ComputerPart} from './ComputerPart';
import {Computer} from './Computer';
import {ComputerPartDisplayVisitor} from './ComputerPartDisplayVisitor';
let computer:ComputerPart = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
因為寫到發現Typescript竟然沒有Overload,就...哎...但繞開的話其實意義不是那麼大了?使用其它套件或是自己寫的套件達成,好像也會讓程式碼變的稍加複雜,期待到時候有解決方法了!
https://www.tutorialspoint.com/design_pattern/visitor_pattern.htm